#include "FSMSystem.h"

void FSMSystem::init()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state to init()
	m_current->init();
}

void FSMSystem::reset()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state to reset() if only it is NOT renawable
	if(!m_current->renew())
		m_current->reset();
}

void FSMSystem::release()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state to release()
	m_current->release();
}

void FSMSystem::input()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state's input()
	m_current->input();
}

void FSMSystem::update()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state's update()
	m_current->update();
}

void FSMSystem::draw()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state's draw()
	m_current->draw();
}

void FSMSystem::pre()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state's preLoop()
	m_current->pre();
}

void FSMSystem::post()
{
	//return if:
	//* system is not power on
	//* OR next boolean was triggered
	//* OR prev boolean was triggered
	if(!m_powered || m_next || m_prev || m_current == 0) return;

	//call the current state's postLoop()
	m_current->post();
}

int FSMSystem::powerOnSystem()
{
	//return if the system is already powered
	if(m_powered) return SYS_SUCCESS;

	//exit with empty if cartridge list is empty
	if(m_fsmList.size() == 0)
		return SYS_CART_EMPTY;

	//set system complete flag to false
	//meaning system operation is not completed
	m_powered = true;

	//grab the first cartridge and init
	//set cartridge loaded flag to true
	//meaning it has been initialized for operation
	m_current = m_fsmList[0];
	m_current->init();
	m_current->m_loaded = true;

	//exit with success
	return SYS_SUCCESS;
}

int FSMSystem::powerOffSystem()
{
	//return if the system is already not powered
	if(!m_powered) return SYS_SUCCESS;

	//set system complete flag to true
	//meaning system operation has been completed
	//null the cartridge slot
	m_powered = false;
	m_current = 0;

	//loop through cartridge slots
	//release and delete and null
	for(int i = 0; i < m_fsmList.size(); i++)
	{
		m_fsmList[i]->release();
		delete m_fsmList[i];
		m_fsmList[i] = 0;
	}

	//release the list
	m_fsmList.release();

	return SYS_SUCCESS;
}

int FSMSystem::checkCartridge()
{
	//return if the system is not powered on
	if(!m_powered) return SYS_SUCCESS;

	//disable next and prev boolean if it's enabled
	if(m_next) m_next = false;
	if(m_prev) m_prev = false;

	//check if current cartridge has completed operation
	//if so, exit with success
	if(!m_current->completed()) return SYS_SUCCESS;

	//if the current state's swapId is the powerOffId
	//then call power off the system and return
	if(m_current->m_swapId == m_powerOffId)
	{
		powerOffSystem();
		return SYS_SUCCESS;
	}

	//swap cartridge if current cartridge is done
	return swapCartridge();
}

int FSMSystem::swapCartridge()
{
	//exit with empty if no cartridge
	if(m_current == 0) return SYS_CART_EMPTY;

	//loop through to find swap cartridge
	for(int i = 0; i < m_fsmList.size(); i++)
	{
		if(m_current->m_swapId == m_fsmList[i]->m_selfId)
		{
			//reset current state
			m_current->m_completed = false;

			//release only if renewable
			if(m_current->renew())
			{
				m_current->m_swapId = m_current->m_selfId;
				m_current->m_loaded = false;
				m_current->release();
			}

			//grab the swap cartridge
			m_current = m_fsmList[i];

			//init only if renewable or
			//is not renewable but has not loaded
			//else if is not renewable, but loaded, call reset()
			if(m_current->renew() || (!m_current->renew() && !m_current->loaded()))
			{
				m_current->m_swapId = m_current->m_selfId;
				m_current->m_loaded = true;
				m_current->m_completed = false;
				m_current->init();
			}
			else if(!m_current->renew() && m_current->loaded())
			{
				m_current->reset();
			}

			//exit with success
			return SYS_SUCCESS;
		}
	}

	//if swap cartridge is not found,
	//release and null current cartidge
	m_current->release();
	m_current = 0;

	//exit with empty
	return SYS_CART_EMPTY;
}

void FSMSystem::nextCartridge()
{
	//exit with empty if
	//cartridge slot is empty or
	//cartridge list is empty
	if(m_current == 0) return;
	if(m_fsmList.size() == 0) return;

	//loop through to obtain current cartridge's
	//index number in the cartridge list
	int idx = -1;
	for(int i = 0; i < m_fsmList.size(); i++)
	{
		if(m_current == m_fsmList[i])
		{
			idx = i;
			break;
		}
	}

	//exit if the index + 1 is greater or equal then the size
	//meaning there is no next cartridge to jump to
	if(idx+1 >= m_fsmList.size()) return;

	//reset current state
	m_current->m_completed = false;

	//release only if renewable
	if(m_current->renew())
	{
		m_current->m_swapId = m_current->m_selfId;
		m_current->m_loaded = false;
		m_current->release();
	}

	//swap with next cartridge in line
	m_current = m_fsmList[idx+1];

	//init only if renewable or
	//is not renewable but has not loaded
	if(m_current->renew() || (!m_current->renew() && !m_current->loaded()))
	{
		m_current->init();
		m_current->m_swapId = m_current->m_selfId;
		m_current->m_loaded = true;
		m_current->m_completed = false;
	}

	//trigger the next boolean on to indicate to
	//the system to not update the current state
	//because this function can be called anywhere
	m_next = true;
}

void FSMSystem::prevCartridge()
{
	//exit with empty if
	//cartridge slot is empty or
	//cartridge list is empty
	if(m_current == 0) return;
	if(m_fsmList.size() == 0) return;

	//loop through to obtain current cartridge's
	//index number in the cartridge list
	int idx = -1;
	for(int i = 0; i < m_fsmList.size(); i++)
	{
		if(m_current == m_fsmList[i])
		{
			idx = i;
			break;
		}
	}

	//exit if the index - 1 is less or equal then zero
	//meaning there is no previous cartridge to jump to
	if(idx-1 < 0) return;

	//reset current state
	m_current->m_completed = false;

	//release only if renewable
	if(m_current->renew())
	{
		m_current->m_swapId = m_current->m_selfId;
		m_current->m_loaded = false;
		m_current->release();
	}

	//swap with next cartridge in line
	m_current = m_fsmList[idx-1];

	//init only if renewable or
	//is not renewable but has not loaded
	if(m_current->renew() || (!m_current->renew() && !m_current->loaded()))
	{
		m_current->init();
		m_current->m_swapId = m_current->m_selfId;
		m_current->m_loaded = true;
		m_current->m_completed = false;
	}

	//trigger the prev boolean on to indicate to
	//the system to not update the current state
	//because this function can be called anywhere
	m_prev = true;
}

void FSMSystem::systemData(void* a_data)
{
	//exit if given data is null
	if(a_data == 0) return;

	//get system data and give all cartridge system data
	m_data = a_data;
	for(int i = 0; i < m_fsmList.size(); i++)
		m_fsmList[i]->m_data = m_data;
}

void FSMSystem::queueCartridge(FSMCartridge* m_cartridge)
{
	//exit if given cartridge is null
	if(m_cartridge == 0) return;

	//give cartridge system data if any
	if(m_data) m_cartridge->m_data = m_data;

	//queue cartridge into cartridge list
	m_fsmList.insertBack(m_cartridge);
}